Skip to content

fix(auth): add secure auth secret storage APIs#38

Closed
echobt wants to merge 2 commits intomainfrom
fix/auth-secure-secret-storage
Closed

fix(auth): add secure auth secret storage APIs#38
echobt wants to merge 2 commits intomainfrom
fix/auth-secure-secret-storage

Conversation

@echobt
Copy link
Contributor

@echobt echobt commented Mar 11, 2026

Summary

  • add allowlisted keyring-backed auth secret commands in the Tauri settings layer
  • extend the secure store with generic secret helpers for auth session blobs
  • add a frontend auth secret storage helper for migrating legacy auth data from browser storage

#[tauri::command]
pub async fn settings_get_auth_secret(key_name: String) -> Result<Option<String>, String> {
validate_auth_secret_name(&key_name)?;
Ok(SecureApiKeyStore::get_secret(&key_name)?.map(|secret| secret.expose_secret().to_string()))

Check failure

Code scanning / CodeQL

Cleartext logging of sensitive information High

This operation writes
...::get_secret(...)
to a log file.

Copilot Autofix

AI 3 days ago

In general, to fix “cleartext logging of sensitive information” you avoid emitting the sensitive value to any logs, traces, or broadly observable outputs. If exposure is necessary, you either redact it, partially mask it, or encrypt it before emission, ensuring downstream logging cannot trivially reveal it.

For this specific code, the core problem is that settings_get_auth_secret exposes the secret value as a String, which any consumer (including UI code and frameworks) can log in plaintext. The best fix that does not break existing call patterns too much is to avoid returning the actual secret and instead only return non-sensitive metadata, such as whether a secret exists for a given key_name. This preserves some functionality (the caller can know if a secret is stored) without disclosing the sensitive material itself. Concretely, in src-tauri/src/settings/commands.rs around line 479–482, we should change the return type from Result<Option<String>, String> to Result<bool, String> and the body to call SecureApiKeyStore::get_secret(&key_name) only to check presence, not to expose its contents. That way, no decrypted secret is converted into a String or passed across the Tauri boundary, eliminating the analyzer’s flagged flow.

To implement this, we only need to modify the function signature and body of settings_get_auth_secret in src-tauri/src/settings/commands.rs. No new methods or imports are necessary. The revised function will:

  • Validate the auth secret name as before.
  • Call SecureApiKeyStore::get_secret(&key_name)?.
  • Return Ok(secret_opt.is_some()), indicating presence/absence without exposing the secret itself.

If the existing frontend truly requires the plaintext secret, the more secure alternative would be to introduce a different, tightly controlled mechanism (e.g., a one-time-use token, or performing necessary operations on the backend without ever returning the secret). Since we cannot change unshown code, we limit ourselves to the safer pattern of not exposing the secret at all.

Suggested changeset 1
src-tauri/src/settings/commands.rs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src-tauri/src/settings/commands.rs b/src-tauri/src/settings/commands.rs
--- a/src-tauri/src/settings/commands.rs
+++ b/src-tauri/src/settings/commands.rs
@@ -474,11 +474,12 @@
     SecureApiKeyStore::set_secret(&key_name, value)
 }
 
-/// Retrieve an auth secret from the keyring
+/// Retrieve the presence status of an auth secret in the keyring without exposing its value
 #[tauri::command]
-pub async fn settings_get_auth_secret(key_name: String) -> Result<Option<String>, String> {
+pub async fn settings_get_auth_secret(key_name: String) -> Result<bool, String> {
     validate_auth_secret_name(&key_name)?;
-    Ok(SecureApiKeyStore::get_secret(&key_name)?.map(|secret| secret.expose_secret().to_string()))
+    let secret_opt = SecureApiKeyStore::get_secret(&key_name)?;
+    Ok(secret_opt.is_some())
 }
 
 /// Delete an auth secret from the keyring
EOF
@@ -474,11 +474,12 @@
SecureApiKeyStore::set_secret(&key_name, value)
}

/// Retrieve an auth secret from the keyring
/// Retrieve the presence status of an auth secret in the keyring without exposing its value
#[tauri::command]
pub async fn settings_get_auth_secret(key_name: String) -> Result<Option<String>, String> {
pub async fn settings_get_auth_secret(key_name: String) -> Result<bool, String> {
validate_auth_secret_name(&key_name)?;
Ok(SecureApiKeyStore::get_secret(&key_name)?.map(|secret| secret.expose_secret().to_string()))
let secret_opt = SecureApiKeyStore::get_secret(&key_name)?;
Ok(secret_opt.is_some())
}

/// Delete an auth secret from the keyring
Copilot is powered by AI and may make mistakes. Always verify output.
@echobt echobt closed this Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant